﻿using System;
using System.Collections.Generic;
using System.Threading;
using CommonTypes.Server;
using CommonTypes.Server.Operations;
using Server.Model;

namespace Server.Services.Primary
{
    public class PrimaryMergingManager : MergingManager
    {
        public static void GenerateTicket( String clientId, ServerData serverData )
        {
            long newLogicalClock = serverData.ServerLogicalClock;
            if( serverData.State == ServerState.ESTABLISHED )
            {
                System.Console.WriteLine( "I'm processing a ticket request." );

                serverData.Operations.Add( newLogicalClock, new TicketGeneration( newLogicalClock, serverData.TicketNumber + 1 ) );

                foreach( KeyValuePair<String, IServerToServer> servers in serverData.ServersInformation.ServersProxy )
                {
                    if( !servers.Key.Equals( serverData.ServerId ) && serverData.ServersInformation.ActiveServers[ servers.Key ] )
                    {
                        try
                        {
                            servers.Value.AcknowledgeTicket( serverData.TicketNumber + 1, clientId, newLogicalClock );
                        }
                        catch
                        {
                            System.Console.WriteLine( String.Format( "Server {0} is down!", servers.Key ) );
                            serverData.ServersInformation.ActiveServers[ servers.Key ] = false;
                            continue;
                        }
                    }
                }

                System.Console.WriteLine( "I've sent the ticket request to all the secondaries." );
            }
        }

        public static bool RegisterClientLocation( String clientId, String clientLocation, ServerData serverData )
        {
            long newLogicalClock = serverData.ServerLogicalClock;
            if( serverData.State == ServerState.ESTABLISHED )
            {
                System.Console.WriteLine( "I'm processing a register request." );

                serverData.Operations.Add( newLogicalClock, new AddOperation( newLogicalClock, clientId, clientLocation ) );

                foreach( KeyValuePair<String, IServerToServer> servers in serverData.ServersInformation.ServersProxy )
                {
                    if( !servers.Key.Equals( serverData.ServerId ) && serverData.ServersInformation.ActiveServers[ servers.Key ] )
                    {
                        try
                        {
                            System.Console.WriteLine( String.Format( "I'm sending the register request to server {0}", servers.Key ) );
                            servers.Value.RegisterClient( clientId, clientLocation, newLogicalClock );
                        }
                        catch
                        {
                            System.Console.WriteLine( String.Format( "Server {0} is down!", servers.Key ) );
                            serverData.ServersInformation.ActiveServers[ servers.Key ] = false;
                            continue;
                        }
                    }
                }

                System.Console.WriteLine( "I've sent the register request to all the secondaries." );
            }
            return true;
        }

        public static bool UnregisterClientLocation( String clientId, ServerData serverData )
        {
            long newLogicalClock = serverData.ServerLogicalClock;
            if( serverData.State == ServerState.ESTABLISHED )
            {
                System.Console.WriteLine( "I'm processing a unregister request." );

                serverData.Operations.Add( newLogicalClock, new RemoveOperation( newLogicalClock, clientId ) );

                foreach( KeyValuePair<String, IServerToServer> servers in serverData.ServersInformation.ServersProxy )
                {
                    if( !servers.Key.Equals( serverData.ServerId ) && serverData.ServersInformation.ActiveServers[ servers.Key ] )
                    {
                        try
                        {
                            servers.Value.UnregisterClient( clientId, newLogicalClock );
                        }
                        catch
                        {
                            System.Console.WriteLine( String.Format( "Server {0} is down!", servers.Key ) );
                            serverData.ServersInformation.ActiveServers[ servers.Key ] = false;
                            continue;
                        }
                    }
                }

                System.Console.WriteLine( "I've sent the unregister request to all the secondaries." );
            }
            return true;
        }

        public static Operation[ ] SynchronizeServer( long logicalClock, ServerData serverData )
        {
            List<Operation> ops = new List<Operation>( );

            lock( ProcessingRequests._requestLock )
            {
                if( serverData.Operations.Count != 0 )
                {
                    for( long i = logicalClock; i < serverData.Operations.Count; i++ )
                    {
                        if( serverData.Operations.ContainsKey( i ) )
                        {
                            System.Console.WriteLine( "I'm adding a operation" );
                            ops.Add( serverData.Operations[ i ] );
                        }
                    }
                }
                Monitor.Pulse( ProcessingRequests._requestLock );
            }

            System.Console.WriteLine( String.Format( "I'm about to send {0} requests.", ops.Count ) );

            return ops.ToArray( );
        }
    }
}